<template>
  <!-- 用户视口：超出部分滚动 -->
  <!-- @scroll="onScroll"  -->
  <div
    ref="viewPort"
    class="viewPort"
    v-debounce="{ eventFunc: onScroll, delay: 0, eventType: 'onscroll' }"
  >
    <!-- 数据列表 -->
    <node-content
      ref="nodeContent"
      :children.sync="showList"
      :flatArr_f="flatArr_f"
      :flatArr="flatArr"
      :offset-top="offsetTop"
      class="list"
      @setCollapse="setCollapse"
      @setExpand="setExpand"
      v-on="$listeners"
      @change="change"
      @nodeClick="nodeClick"
      :selectArr_f.sync="selectArr_f"
      v-bind="$attrs"
      :filterText="filterText"
      :keys="keys"
    />
    <!-- 子元素超出父元素高度 -->
    <div ref="scrollView" class="scrollView" />
  </div>
</template>

<script>
import nodeContent from "./node-content.vue";
export default {
  components: { nodeContent },
  props: {
    inputTree: {
      type: Object,
      require: true,
    },
    // 树的数据
    initTreeData: {
      type: Array,
    },
    // 树数据的接口
    treeDataInterfaceName: {
      type: Function,
    },
    // 选中值的数组
    selectedNodes: {
      type: Array,
      require: true,
    },
    // 行高
    rowHeight: {
      type: Number,
      default: 16,
    },
    // 显示多少条数据
    viewCount: {
      type: Number,
      default: 10,
    },
    //初始化子元素展开还是折叠
    isExpand: {
      type: Boolean,
      default: false,
    },
    // 树的筛选条件
    filterText: {
      type: String,
    },
    // 全选框的值
    checked: {
      type: Boolean,
    },
  },
  data() {
    return {
      keys: this.inputTree.keys,
      treeData: [], //正常树
      filterTreeData: [], //筛选树
      flatArr: [],
      flatArr_f: [],
      allNodes: [], //正常树的全部节点备份
      filterAllNodes: [], //筛选树的全部节点备份
      start: 0,
      end: this.viewCount,
      // rowHeight: 16, // 行高
      // viewCount: 10, // 显示多少条数据
      offsetTop: null, // 视口偏移量
      // isExpand: false,//初始化子元素展开还是折叠
      isSelectAll: false, //是否全选
      selectArr_f: [],
      motherArr: [], //筛选项祖宗节点数组
      hideNodes: [],
      recordHandlerNodes: [], //完整树操作节点数组
    };
  },
  computed: {
    showList: {
      get() {
        return this.flatArr.slice(this.start, this.end);
      },
      set(v) {
        // console.log("showList:");
        // console.log(v);
      },
    },
  },
  watch: {
    filterText(newVal, oldVal) {
      this.$refs.viewPort.scrollTop = 0;
      //进
      if (!oldVal && newVal) {
        this.flatArr_f = [...this.flatArr];
      }
      // 出
      if (!newVal && oldVal) {
        this.flatArr.splice(0, this.flatArr.length);
        this.flatArr = [...this.flatArr_f];
        this.flatArr_f.splice(0, this.flatArr_f.length);
      }
      //筛选过程
      if (newVal) {
        this.motherArr.splice(0, this.motherArr.length);
        // 全选用到
        this.filterAllNodes.splice(0, this.filterAllNodes.length);
        // 获取筛选树
        this.getFilterTree(newVal);
        // 设置筛选树节点和完整树一样
        this.setFilterTreeLikeHandler(this.motherArr, this.recordHandlerNodes);
        this.flatArr = [...this.motherArr];
      }
      this.setListStyle();
    },
    treeDataInterfaceName: {
      handler(newVal) {
        if (typeof newVal === "function") {
          console.log("走接口");
          this.getTreeData();
        } else {
          this.$nextTick(() => {
            if (this.initTreeData && this.initTreeData.length > 0) {
              console.log("走数据");
              this.initTree(this.initTreeData);
            } else {
              console.error("请传入树的数据");
            }
          });
        }
      },
      immediate: true,
    },
  },
  mounted() {
    // if (this.initTreeData.length > 0) {
    //   this.treeData = JSON.parse(JSON.stringify(this.initTreeData));
    //   // 供筛选用
    //   this.filterTreeData = JSON.parse(JSON.stringify(this.initTreeData));
    //   this.initTree();
    // } else {
    //   this.getTreeData().then(
    //     (res) => {
    //       console.log(res);
    //       this.initTree();
    //     },
    //     (error) => {
    //       console.log(error);
    //     }
    //   );
    // }
  },
  methods: {
    getTreeData() {
      this.treeDataInterfaceName().then((res) => {
        if (res.status == 200) {
          // this.treeData = JSON.parse(JSON.stringify(res.data.treeData));
          // // 供筛选用
          // this.filterTreeData = JSON.parse(JSON.stringify(res.data.treeData));
          // return Promise.resolve("get data success");
          this.initTree(res.data.treeData);
        }
      });
    },
    initTree(data) {
      this.treeData = JSON.parse(JSON.stringify(data));
      // 供筛选用
      this.filterTreeData = JSON.parse(JSON.stringify(data));
      //  初始化列表
      this.initList(this.flatArr, this.treeData, false, true);
      this.setListStyle();

      if (this.inputTree.hasOwnProperty("defaultKeys")) {
        // 设置树节点和默认值一样
        let defaultSelectArr = new Array();
        this.setFilterTreeLikeHandler(
          this.flatArr,
          this.inputTree.defaultKeys,
          defaultSelectArr
        );
        this.$emit("update:selectedNodes", defaultSelectArr);
      }
    },
    // 初始化数据
    initList(arr, nodes, needBackups = false) {
      nodes.forEach((item) => {
        let n = 0;
        this.$set(item, "level", n); //层级
        this.$set(item, "checked", this.isSelectAll); //全选-取消

        if (item.hasOwnProperty(this.keys.childKey)) {
          this.$set(item, "caretFlag", this.isExpand); //下拉箭头展示折叠
          this.$set(item, "indeterminate", this.isSelectAll); //半选
          if (!this.isExpand) {
            item["hideNodes"] = item[this.keys.childKey]; //初始化折叠状态下的子孙后代元素取直接子元素
          }
        } else {
          this.$set(item, "indeterminate", false); //半选
        }
        arr.push(item);
        if (needBackups) {
          // 备份全选数据
          this.allNodes.push(item);
        } else {
          this.filterAllNodes.push(item);
        }

        if (item.hasOwnProperty(this.keys.childKey)) {
          this.flatListData(
            arr,
            item[this.keys.childKey],
            ++n,
            item,
            needBackups
          );
        }
      });
    },
    flatListData(arr, nodes, n, motherItem, needBackups) {
      ++n;
      nodes.forEach((item) => {
        this.$set(item, "level", n);
        this.$set(item, "checked", this.isSelectAll);
        this.$set(item, "mother", motherItem); //当前节点的母元素

        if (item.hasOwnProperty(this.keys.childKey)) {
          this.$set(item, "caretFlag", this.isExpand);
          this.$set(item, "indeterminate", this.isSelectAll);
          if (!this.isExpand) {
            item["hideNodes"] = item[this.keys.childKey]; //初始化折叠状态下的子孙后代元素取直接子元素
          }
        } else {
          this.$set(item, "indeterminate", false); //半选
        }

        if (this.isExpand) {
          arr.push(item);
        }
        if (needBackups) {
          // 备份全选数据
          this.allNodes.push(item);
        } else {
          this.filterAllNodes.push(item);
        }
        if (item.hasOwnProperty(this.keys.childKey)) {
          this.flatListData(
            arr,
            item[this.keys.childKey],
            n,
            item,
            needBackups
          );
        }
      });
    },
    // 设置及清空全选
    clear(flag) {
      // 清空记录完整树操作节点
      this.$refs.nodeContent.clearRecord();
      this.isSelectAll = flag;
      // 清空正常树展示全选或取消全选-展示层面非选中层面
      this.clearSellectAll(this.allNodes, flag);
      // 设置筛选树展示全选或取消全选-展示层面非选中层面
      this.clearSellectAll(this.filterAllNodes, flag);
      //设置选中项数组-只需正常树的
      this.selectArr_f.splice(0, this.selectArr_f.length);
      if (flag) {
        this.allNodes.forEach((item) => {
          this.selectArr_f.push(item);
        });
      }
      return this.selectArr_f;
    },
    // 设置及清空全选
    clearSellectAll(nodes, flag) {
      nodes.forEach((item) => {
        this.$set(item, "checked", flag); //全选-取消
        if (item.hasOwnProperty(this.keys.childKey)) {
          this.$set(item, "indeterminate", flag); //半选
          this.clearSellectAll(item[this.keys.childKey]);
        }
      });
    },
    // 设置虚拟滚动样式
    setListStyle() {
      this.$refs.scrollView.style.height =
        this.flatArr.length * (this.rowHeight + 8) + "px";
      this.$refs.viewPort.style.height =
        this.viewCount * (this.rowHeight + 8) + "px";
    },
    onScroll() {
      this.offsetTop = this.$refs.viewPort.scrollTop;
      this.start = Math.round(this.offsetTop / (this.rowHeight + 8));
      this.end = this.start + this.viewCount;
    },
    // 折叠
    setCollapse(indexArr, nodes) {
      this.flatArr.splice(this.start + indexArr[0], indexArr[1]);
      // 折叠重新调用子元素超出父元素高度（数组长度已变，直接调用即可）
      this.setListStyle();
    },
    // 展开
    setExpand(index, nodes) {
      this.flatArr.splice(this.start + index, 0, ...nodes.hideNodes);
      // 展开重新调用设置子元素超出父元素高度（数组长度已变，直接调用即可）
      this.setListStyle();
    },
    // 设置节点属性值，attributeObj-要设置的属性对象,judgesAttribute-判断是否有什么元素
    setNodes(nodes, attributeObj, judgesAttribute) {
      nodes.forEach((item) => {
        Object.keys(attributeObj).forEach((keys) => {
          this.$set(item, keys, attributeObj[keys]);
        });
        if (item.hasOwnProperty(judgesAttribute)) {
          this.setNodes(item[judgesAttribute], attributeObj, judgesAttribute);
        }
      });
    },
    // 获取筛选项树
    getFilterTree(filterText) {
      const remoteTreeData = this.filterTreeData || [];
      let fliterRemoteTreeData = [];
      // 搜索
      if (filterText) {
        const filterTree = function (text, tree, treeKeys, nodes) {
          tree.forEach((item) => {
            // 如果父节点包含筛选条件，则放进去
            if (
              item[treeKeys.textKey].indexOf(text) !== -1 &&
              !item[treeKeys.childKey]
            ) {
              nodes.push(item);
            }
            if (item[treeKeys.childKey] && item[treeKeys.childKey].length > 0) {
              let getNodes = [];

              getNodes = filterTree(
                text,
                item[treeKeys.childKey],
                treeKeys,
                []
              );
              // 如果子节点包含筛选条件不管父节点有没有包含筛选条件，父节都需要放进去
              if (getNodes.length > 0) {
                let item_f = JSON.parse(JSON.stringify(item));
                item_f.nodes = JSON.parse(JSON.stringify(getNodes));
                nodes.push(item_f);
              } else {
                // 如果子节点不包含筛选条件，但是父节点包含，则父节点需要删除子节点后再放进去
                if (item[treeKeys.textKey].indexOf(text) !== -1) {
                  let item_f = JSON.parse(JSON.stringify(item));
                  delete item_f[treeKeys.childKey];
                  nodes.push(item_f);
                }
              }
            }
          });

          return nodes;
        };
        fliterRemoteTreeData = filterTree(
          filterText,
          remoteTreeData,
          this.keys,
          []
        );
      }
      // return fliterRemoteTreeData
      //  初始化列表
      this.initList(this.motherArr, fliterRemoteTreeData, true);
    },

    //复选框事件
    change(node, status, nodes, recordHandlerNodes) {
      this.recordHandlerNodes.splice(
        this.recordHandlerNodes.length,
        0,
        ...recordHandlerNodes
      );
      this.updateAllSelect(node, nodes);
      this.$emit("change", node, status, nodes);
    },
    nodeClick(node, status, nodes, recordHandlerNodes) {
      this.recordHandlerNodes.splice(
        this.recordHandlerNodes.length,
        0,
        ...recordHandlerNodes
      );
      this.updateAllSelect(node, nodes);
      this.$emit("nodeClick", node, status, nodes);
    },
    // 更新全选
    updateAllSelect(node, nodes) {
      if (!node.checked) {
        this.$emit("update:checked", false);
      } else {
        if (nodes.length === this.allNodes.length) {
          this.$emit("update:checked", true);
        }
      }
    },
    // 设置筛选树及完全树选中项
    setFilterTreeLikeHandler(filterTree, likeNodes, defaultSelectArr) {
      let likeNodes_f = [...likeNodes];
      filterTree.forEach((ele) => {
        likeNodes_f.forEach((item, index) => {
          if (
            ele[this.keys.valueKey] ==
            (item.hasOwnProperty(this.keys.valueKey)
              ? item[this.keys.valueKey]
              : item)
          ) {
            likeNodes_f.splice(index, 1);
            if (item.hasOwnProperty(this.keys.valueKey)) {
              ele.checked = item.checked;
              ele.indeterminate = item.indeterminate;
            } else {
              ele.checked = true;
              if (ele.hasOwnProperty(this.keys.childKey)) {
                ele.indeterminate = true;
              }
              this.selectArr_f.splice(this.selectArr_f.length, 0, ele);
              this.recordHandlerNodes.splice(
                this.recordHandlerNodes.length,
                0,
                ele
              );
              defaultSelectArr.splice(defaultSelectArr.length, 0, ele);
            }

            // 有祖宗
            if (ele.hasOwnProperty("mother")) {
              this.$refs.nodeContent.changeSelect_single(ele.mother, "mother");
            }
          }
        });
        if (ele.hasOwnProperty(this.keys.childKey)) {
          this.setFilterTreeLikeHandler(
            ele[this.keys.childKey],
            likeNodes_f,
            defaultSelectArr
          );
        }
      });
    },
  },
};
</script>

<style>
.viewPort {
  margin-top: 10px;
  position: relative;
  width: inherit;
  /* background-color: aquamarine; */
  overflow-y: scroll;
}

.list {
  position: absolute;
  top: 0;
  left: 0;
}
</style>
